﻿using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.Linq.Extensions;
using Partner.Surround.Authorization.Users;
using Partner.Surround.Authorization.Roles.Dto;
using Microsoft.EntityFrameworkCore;
using Partner.Surround.Authorization.Permissions.Dto;

namespace Partner.Surround.Authorization.Roles
{
    /// <summary>
    /// 角色应用服务实现
    /// </summary>
    public class RoleAppService : SurroundAppServiceBase, IRoleAppService
    {
        #region 初始化
        private readonly RoleManager _roleManager;
        private readonly UserManager _userManager;
        private readonly IRepository<Role> _roleRepository;

        public RoleAppService(IRepository<Role> roleRepository, RoleManager roleManager, UserManager userManager)
        {
            _roleManager = roleManager;
            _userManager = userManager;
            _roleRepository = roleRepository;
        }
        #endregion

        #region 角色管理
        public async Task<ListResultDto<RoleDto>> GetAllRole()
        {
            var roles = await _roleRepository.GetAllListAsync();
            return new ListResultDto<RoleDto>(ObjectMapper.Map<List<RoleDto>>(roles));
        }

        public async Task<PagedResultDto<RoleListDto>> GetPagedRole(GetPagedRoleInput input)
        {
            var query = _roleRepository.GetAll();

            var totalCount = await query.CountAsync();
            var items = await query.PageBy(input).ToListAsync();

            return new PagedResultDto<RoleListDto>(
                totalCount,
                items.Select(item =>
                {
                    var dto = ObjectMapper.Map<RoleListDto>(item);
                    //扩展处理...
                    return dto;
                }).ToList());
        }

        public async Task<GetRoleForEditOutput> GetRoleForEdit(NullableIdDto input)
        {
            var permissions = PermissionManager.GetAllPermissions();
            var grantedPermissions = new Permission[0];
            var roleEditDto = new RoleEditDto();

            if (input.Id.HasValue)
            {
                var role = await _roleManager.GetRoleByIdAsync(input.Id.Value);
                grantedPermissions = (await _roleManager.GetGrantedPermissionsAsync(role)).ToArray();
                roleEditDto = ObjectMapper.Map<RoleEditDto>(role);
            }

            return new GetRoleForEditOutput
            {
                Role = roleEditDto,
                Permissions = ObjectMapper.Map<List<FlatPermissionDto>>(permissions).OrderBy(p => p.DisplayName).ToList(),
                GrantedAppPermissions = grantedPermissions.Select(p => p.Name).ToList()
            };
        }

        public async Task CreateOrUpdateRole(CreateOrUpdateRoleInput input)
        {
            if (!input.Role.Id.HasValue)
            {
                await CreateRole(input);
            }
            else
            {
                await UpdateRole(input);
            }
        }

        /// <summary>
        /// 创建角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AbpAuthorize(PermissionNames.Pages_Frame_Roles_Create)]
        private async Task CreateRole(CreateOrUpdateRoleInput input)
        {
            var role = ObjectMapper.Map<Role>(input.Role);
            role.SetNormalizedName();

            CheckErrors(await _roleManager.CreateAsync(role));

            var grantedPermissions = PermissionManager
                .GetAllPermissions()
                .Where(p => input.PermissionNames.Contains(p.Name))
                .ToList();

            await _roleManager.SetGrantedPermissionsAsync(role, grantedPermissions);
        }

        /// <summary>
        /// 更新角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AbpAuthorize(PermissionNames.Pages_Frame_Roles_Update)]
        private async Task UpdateRole(CreateOrUpdateRoleInput input)
        {
            var role = await _roleManager.GetRoleByIdAsync(input.Role.Id.Value);

            ObjectMapper.Map(input.Role, role);

            CheckErrors(await _roleManager.UpdateAsync(role));

            var grantedPermissions = PermissionManager
                .GetAllPermissions()
                .Where(p => input.PermissionNames.Contains(p.Name))
                .ToList();

            await _roleManager.SetGrantedPermissionsAsync(role, grantedPermissions);
        }

        [AbpAuthorize(PermissionNames.Pages_Frame_Roles_Delete)]
        public async Task DeleteRole(List<EntityDto<int>> inputs)
        {
            foreach (var input in inputs)
            {
                var role = await _roleManager.FindByIdAsync(input.Id.ToString());
                var users = await _userManager.GetUsersInRoleAsync(role.NormalizedName);

                foreach (var user in users)
                {
                    CheckErrors(await _userManager.RemoveFromRoleAsync(user, role.NormalizedName));
                }

                CheckErrors(await _roleManager.DeleteAsync(role));
            }
        }
        #endregion
    }
}

